package com.notary.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfWriter;
import com.lowagie.text.Document;
import com.lowagie.text.Image;
import com.lowagie.text.Rectangle;

import com.notary.entity.Contract;
import com.notary.entity.Person;
import com.notary.entity.po.PrintDto;
import com.notary.entity.vo.JsonResult;
import com.notary.service.ContractService;
import com.notary.service.PersonService;
import com.notary.util.MD5Utils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.http.entity.ContentType;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.printing.PDFPrintable;
import org.apache.pdfbox.printing.Scaling;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import sun.misc.BASE64Encoder;
import sun.security.tools.PathList;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.print.*;

import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Sides;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.print.*;
import java.io.*;

import java.net.URL;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.zip.ZipEntry;

import java.util.zip.ZipOutputStream;

@Api(tags = "打印文件")
@RestController
@RequestMapping("/print")
public class PrintController {
    @Autowired
    private OSS ossClient;

    @Value("${aliyun.bucketName}")
    private String bucketName;

    @Value("${aliyun.urlPrefix}")
    private String urlPrefix;

    @Value("${aliyun.folderName}")
    private String folderName;

    @Resource
    ContractService contractService;
    @Resource
    PersonService personService;

    public static void main(String[] args) {
        String base = encryptToBase64("");
        System.out.println(base);
    }

    @ApiOperation(value = "打印材料")
    @PostMapping("/printFiles")
    public JsonResult printFiles(@RequestBody PrintDto dto) throws Exception{
        System.out.println("前段传过来的dto:"+dto);
//        if (dto.getPrinter() == null){
//            return JsonResult.fail("传入打印机为空");
//        }
        if(dto.getPathList().length == 0){
            return JsonResult.fail("传入文件为空");
        }
        String[] pathList = dto.getPathList();
//       创建一个文件夹存放所有的文件  所有操作完成后 删除这个文件夹
        //获取本机桌面的路径
        File desktopDir = FileSystemView.getFileSystemView() .getHomeDirectory();
        String desktopDirAbsolutePath = desktopDir.getAbsolutePath();
        desktopDirAbsolutePath = desktopDirAbsolutePath+"/imgToPdf";
        File pdfFiles = new File(desktopDirAbsolutePath);
        if (!pdfFiles.getParentFile().exists()){
            pdfFiles.mkdir();
        }

        /*1.先循环将URL的文件都下载至制定文件夹
        * 2.将图片改成PDF
        * 3.将文件路径数组的JPG等后缀都改成PDF
        * 4.将所有的PDF合并成一个PDF
        * */
        String[] localFilePath = new String[pathList.length];
        for (int i = 0; i < pathList.length; i++) {
            File file = getNetUrlHttp(pathList[i], desktopDirAbsolutePath);
            localFilePath[i] = file.getPath();

            //获取URL中的文件名
            String fileFixName = file.getPath().substring(file.getPath().lastIndexOf("/") + 1);
            System.out.println("fileFixName:"+fileFixName);
            //拼装成存在本地的路径
            localFilePath[i] = desktopDirAbsolutePath + "/" +fileFixName;
            System.out.println("localFilePath文件的路径为:"+localFilePath[i]);
        }
        //此时localFilePath中存的是下载到制定文件夹的文件的路径(包含图片以及pdf)
        for (int i = 0; i < localFilePath.length; i++) {
            if (localFilePath[i].substring(localFilePath[i].lastIndexOf(".")+1).equalsIgnoreCase("jpg") ||
                localFilePath[i].substring(localFilePath[i].lastIndexOf(".")+1).equalsIgnoreCase("png") ||
                localFilePath[i].substring(localFilePath[i].lastIndexOf(".")+1).equalsIgnoreCase("jpge") ){
                String path = imgToPDF(localFilePath[i]);
                localFilePath[i] = path;
            }
            System.out.println("处理后现在的本地文件路径为:"+localFilePath[i]);
        }
        Date date = new Date();
        //获取当前时间
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
        String format = simpleDateFormat.format(date);
        System.out.println(format);
        //将多个pdf合并成一个pdf
        String mergePdfFilePath = mergePdfFile(localFilePath, desktopDirAbsolutePath +"/"+ format + ".pdf");
        String base64 = encryptToBase64(mergePdfFilePath);

        //将合并后的PDF文件下载,进行Base64加密
//        File file = getNetUrlHttp(pathList[0]);
//        System.out.println("生成的文件地址为"+file.getPath());
        System.out.println("所有材料存的文件夹为："+desktopDirAbsolutePath);
        deleteDiretory(desktopDirAbsolutePath);
        return JsonResult.success(base64);

    }

    @ApiOperation(value = "电脑连接的打印机列表")
    @PostMapping("/printerList")
    public JsonResult printerList(){
        PrinterJob printerJob = PrinterJob.getPrinterJob();
        PrintService[] printServices = PrinterJob.lookupPrintServices();
        ArrayList<String> printerList = new ArrayList<>();
        for (int i = 0;i < printServices.length; i++) {
            System.out.println("电脑连接的打印机有:"+printServices[i].getName());
            printerList.add(printServices[i].getName());
        }
        Map<String, Object> map = new HashMap<>();
        map.put("printerList",printerList);
        return JsonResult.success(map);
    }

    @ApiOperation(value = "打包下载文件")
    @PostMapping("/downloadToZIP")
    public JsonResult downloadToZIP(@RequestBody PrintDto dto) throws Exception {
        String pingtai = "无平台";
        String personName = "无当事人";
        String contractType = "卷宗包";

        System.out.println("前段传过来的dto:"+dto);
        if(dto.getPathList().length == 0){
            return JsonResult.fail("传入文件为空");
        }
        //获取本机桌面地址
        File desktopDir = FileSystemView.getFileSystemView() .getHomeDirectory();
        String desktopDirAbsolutePath = desktopDir.getAbsolutePath();
        System.out.println("本机桌面地址为:"+desktopDirAbsolutePath);
        //下载地址
        String donloadPath = desktopDirAbsolutePath+"/downloadFilesToZIP";

        Contract contract = contractService.getOne(new QueryWrapper<Contract>().eq("id",dto.getContractId()));
        Person person = personService.getOne(new QueryWrapper<Person>().eq("contract_id", dto.getContractId()));

        if (contract.getOrg() != null){
            pingtai  = contract.getOrg();
        }
        if (person.getName() != null) {
            personName = person.getName();
        }
        if (dto.getContractType().equalsIgnoreCase("1")){
            contractType = "公证卷宗包";
        }
        if (dto.getContractType().equalsIgnoreCase("2")){
            contractType = "执行卷宗包";
        }
        //获取最后打包的zip文件的路径以及名字
        desktopDirAbsolutePath = desktopDirAbsolutePath+"/"+pingtai+"-"+personName+"-"+contractType+".zip";
        System.out.println("最后打包文件路径在："+desktopDirAbsolutePath);
        String[] pathList = dto.getPathList();
        File zipFile = new File(desktopDirAbsolutePath);
        ZipOutputStream zipStream = null;
        FileInputStream zipSource = null;
        BufferedInputStream bufferStream = null;
        InputStream inputStream = null;
        try {
            //构造最终压缩包的输出流
            zipStream = new ZipOutputStream(new FileOutputStream(zipFile));

            for (int i = 0; i < pathList.length; i++) {
                File file = getNetUrlHttp(pathList[i],donloadPath);
                //对本地文件命名，path是http的完整路径，主要得到资源的名字
                String newUrl = pathList[i];
                newUrl = newUrl.split("[?]")[0];
                String[] bb = newUrl.split("/");
                //得到最后一个分隔符后的名字
                String fileName = bb[bb.length - 1];
                if (donloadPath == null){
                    return null;
                }
                //保存到本地的路径
                String filePath=donloadPath+"/"+fileName;
                System.out.println("保存到本地的路径为"+filePath);
                file = new File(filePath);
                if(!file.getParentFile().exists()){
                    file.getParentFile().mkdirs();
                }else {
                }
                try{
                    //创建文件
                    file.createNewFile();
                }catch (Exception e){
                    e.printStackTrace();
                }
                //下载
                URL urlfile = new URL(newUrl);
                inputStream = urlfile.openStream();

                //将需要压缩的文件格式化为输入流
//                zipSource = new FileInputStream(file);
                //压缩条目不是具体独立的文件，而是压缩包文件列表中的列表项，称为条目，就像索引一样
                ZipEntry zipEntry = new ZipEntry(file.getName());
                //定位该压缩条目位置，开始写入文件到压缩包中
                zipStream.putNextEntry(zipEntry);
                //输入缓冲流
                bufferStream = new BufferedInputStream(inputStream, 1024 * 10);
                int read = 0;
                //创建读写缓冲区
                byte[] buf = new byte[1024 * 10];
                while((read = bufferStream.read(buf, 0, 1024 * 10)) != -1){
                    zipStream.write(buf, 0, read);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try {
                if(null != bufferStream) bufferStream.close();
                if(null != zipStream) zipStream.close();
                if(null != zipSource) zipSource.close();
                if(null != inputStream) inputStream.close();
                boolean b = deleteDiretory(donloadPath);
                System.out.println(b);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        FileInputStream fileInputStream = null;
        MultipartFile multipartFile = null;
        try {
            fileInputStream = new FileInputStream(zipFile);
            multipartFile = new MockMultipartFile(zipFile.getName(),zipFile.getName(),
                    ContentType.APPLICATION_OCTET_STREAM.toString(),fileInputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
        JsonResult result = uploadFile(multipartFile,pingtai+"-"+personName+"-"+contractType);
        zipFile.delete();
        System.out.println(result);
        JSONObject object=new JSONObject();
        object.put("result",result);
        object.put("fileName",pingtai+"-"+personName+"-"+contractType+".zip");
        return JsonResult.success(object);
    }

//    通过URL下载文件并保存到桌面
    private File getNetUrlHttp(String path) throws Exception{
        //对本地文件命名，path是http的完整路径，主要得到资源的名字
        String newUrl = path;
        newUrl = newUrl.split("[?]")[0];
        String[] bb = newUrl.split("/");
        //得到最后一个分隔符后的名字
        String fileName = bb[bb.length - 1];
        //获取本机桌面的路径
        File desktopDir = FileSystemView.getFileSystemView() .getHomeDirectory();
        String desktopDirAbsolutePath = desktopDir.getAbsolutePath();

        //保存到本地的路径
        String filePath=desktopDirAbsolutePath+"\\"+fileName;
        System.out.println("保存到本地的路径为"+filePath);
        File file = null;

        URL urlfile;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try{
            //判断文件的父级目录是否存在，不存在则创建
            file = new File(filePath);
            if(!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }else {
            }
            try{
                //创建文件
                file.createNewFile();
            }catch (Exception e){
                e.printStackTrace();
            }
            //下载
            urlfile = new URL(newUrl);
            inputStream = urlfile.openStream();
            outputStream = new FileOutputStream(file);

            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead=inputStream.read(buffer,0,8192))!=-1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (null != outputStream) {
                    outputStream.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        ;
        return file;
    }

    //    通过URL下载文件并保存到指定路径
    private File getNetUrlHttp(String path,String fileSavePath) throws Exception{
        //对本地文件命名，path是http的完整路径，主要得到资源的名字
        String newUrl = path;
        newUrl = newUrl.split("[?]")[0];
        String[] bb = newUrl.split("/");
        //得到最后一个分隔符后的名字
        String fileName = bb[bb.length - 1];
        if (fileSavePath == null){
            return null;
        }
        //保存到本地的路径
        String filePath=fileSavePath+"/"+fileName;
        System.out.println("保存到本地的路径为"+filePath);
        File file = null;

        URL urlfile;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try{
            //判断文件的父级目录是否存在，不存在则创建
            file = new File(filePath);
            if(!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }else {
            }
            try{
                //创建文件
                file.createNewFile();
            }catch (Exception e){
                e.printStackTrace();
            }
            //下载
            urlfile = new URL(newUrl);
            inputStream = urlfile.openStream();
            outputStream = new FileOutputStream(file);

            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead=inputStream.read(buffer,0,8192))!=-1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (null != outputStream) {
                    outputStream.close();
                }
                if (null != inputStream) {
                    inputStream.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return file;
    }


    //根据路径删除文件夹
    public boolean deleteDiretory(String pathName){
        boolean flag = false;
        //根据路径创建文件对象
        File directory = new File(pathName);
        //如果路径是一个目录且不为空时，删除目录
        if(directory.isDirectory()&&directory.exists()){
            //获取目录下的所有的目录和文件，放入数组files中
            File[] files = directory.listFiles();
            //遍历目录下的所有的文件和目录
            for(int i= 0;i<files.length;i++){
                //如果目录下是文件时，调用deleteFiles（）方法，删除单个文件
                if (files[i].isFile()){
                    flag = deleteFiles(files[i].getAbsolutePath());
                }//如果目录下是目录时，调用自身deleteDirectory()，形成递归调用
                else{
                    flag = deleteDiretory(files[i].getAbsolutePath());
                }
            }

            //删除目录本身，如果想要保留目录只删除文件，此句可以不要
            flag = directory.delete();
        }
        //删除成功时返回true，失败时返回false
        return flag;
    }

    /**
     * 删除单个文件
     * @param pathName  删除文件路径名
     * @return
     */
    public boolean deleteFiles(String pathName){
        boolean flag = false;
        //根据路径创建文件对象
        File file = new File(pathName);
        //路径是个文件且不为空时删除文件
        if(file.isFile()&&file.exists()){
            flag = file.delete();
        }
        //删除失败时，返回false
        return flag;
    }

    //将文件上传到阿里云
    public JsonResult uploadFile(MultipartFile file,String UpfileName) {
        String fileName = file.getOriginalFilename();
        String md5File="";
        String key = folderName+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddhhmmss"))+ "/" // 时间戳 文件目录
                + UpfileName
                + fileName.substring(fileName.lastIndexOf(".")); // 文件后缀1
        try {
            ossClient.putObject(bucketName, key, file.getInputStream());
            md5File= MD5Utils.MD5Hash(file.getInputStream());
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResult.fail("9999","上传失败");
        }
        JSONObject object=new JSONObject();
        object.put("urf",urlPrefix + key);
        object.put("md5",md5File);
        return JsonResult.success(object);
    }

    //文件BASE64加密
    public static String encryptToBase64(String filePath){
        BASE64Encoder encoder = new BASE64Encoder();
        FileInputStream fin = null;
        BufferedInputStream bin = null;
        ByteArrayOutputStream baos = null;
        BufferedOutputStream bout = null;
        File file = new File(filePath);
        try {
            fin = new FileInputStream(file);
            bin = new BufferedInputStream(fin);
            baos = new ByteArrayOutputStream();
            bout = new BufferedOutputStream(baos);
            byte[] buffer = new byte[1024];
            int len = bin.read(buffer);
            while (len != -1){
                bout.write(buffer,0,len);
                len = bin.read(buffer);
            }
            bout.flush();
            byte[] bytes = baos.toByteArray();
            return encoder.encodeBuffer(bytes).trim();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                fin.close();
                bin.close();
                bout.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return null;
    }

    //将图片转成pdf
    public static String imgToPDF(String imageFolderPath){
        System.out.println("正在调用imgToPDF方法");
        System.out.println("传入的图片路径为:"+imageFolderPath);
        if (imageFolderPath == null){
            return "";
        }
        String pdfPath = imageFolderPath.substring(0,imageFolderPath.lastIndexOf("."));//如果想获得不带点的后缀，变为fileName.lastIndexOf(".")+1
        pdfPath += ".pdf";
        System.out.println("pdfPath转成的PDF路径为:"+pdfPath);
        try {
            long start = System.currentTimeMillis();
            // 图片地址
            FileOutputStream fos = new FileOutputStream(pdfPath);
            // 创建文档
            Document doc = new Document(null, 00, 00, 0, 0);
            // 写入PDF文档
            PdfWriter.getInstance(doc, fos);
            // 读取图片流
            BufferedImage img;
            // 实例化图片
            Image image;
            // 获取图片文件夹对象
            File file = new File(imageFolderPath);
            // 循环获取图片文件夹内的图片

            if (file.getName().endsWith(".png") || file.getName().endsWith(".jpg") || file.getName().endsWith(".gif")
                    || file.getName().endsWith(".jpeg") || file.getName().endsWith(".tif")) {
                // 读取图片流
                img = ImageIO.read(file);
                // 根据图片大小设置文档大小
                doc.setPageSize(new Rectangle(img.getWidth(), img.getHeight()));
                // 实例化图片
                image = Image.getInstance(imageFolderPath);
                // 添加图片到文档
                doc.open();
                doc.add(image);
            }

//            LOGGER.info("fileName is list={}", list);
            // 关闭文档
            doc.close();
            long endTime = System.currentTimeMillis();
            int time = (int) ((endTime - start) / 1000);
//            LOGGER.info("用时：{}:秒！",time);
        } catch (Exception e) {
//            LOGGER.error(e.getMessage());
            e.printStackTrace();
        }
        return pdfPath;
    }

    //将多个pdf合并成一个pdf的方法
    public static String mergePdfFile(String[] files,String newFile) {
        Document document = null;
        try {
            document = new Document(new PdfReader(files[0]).getPageSize(1));
            PdfCopy copy = new PdfCopy(document, new FileOutputStream(newFile));
            document.open();
            for (int i = 0; i < files.length; i++) {
                PdfReader reader = new PdfReader(files[i]);
                int n = reader.getNumberOfPages();
                for(int j=1; j<=n;j++){
                    document.newPage();
                    PdfImportedPage page = copy.getImportedPage(reader, j);
                    copy.addPage(page);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            document.close();
        }
        return newFile;
    }


}
